﻿using System;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32;
using System.Management;

public class ServiceManager
{
    public static void InstallService(int port)
    {
        string exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
        Console.WriteLine($"安装路径: {exePath}");
        Console.WriteLine($"端口号: {port}");

        IntPtr scm = OpenSCManager(null, null, 0x0002); // SC_MANAGER_CREATE_SERVICE
        if (scm == IntPtr.Zero)
        {
            Console.WriteLine("无法打开服务控制管理器");
            return;
        }

        IntPtr service = CreateService(
            scm,
            "MyHttpService_" + port,
            "MyHttpService_" + port,
            0xF01FF, // SERVICE_ALL_ACCESS
            0x00000010, // SERVICE_WIN32_OWN_PROCESS
            0x00000002, // SERVICE_AUTO_START
            0x00000001, // SERVICE_ERROR_NORMAL
            $"\"{exePath}\" {port}", // 确保端口号作为参数传递
            null, (IntPtr)null, null, null, null);

        if (service == IntPtr.Zero)
        {
            Console.WriteLine("无法创建服务");
        }
        else
        {
            Console.WriteLine("服务安装成功");

            // 尝试启动服务
            if (StartService(service, 0, null))
            {
                Console.WriteLine("服务启动成功");
            }
            else
            {
                Console.WriteLine("服务启动失败");
            }

            // 将端口号写入注册表
            using (RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SYSTEM\CurrentControlSet\Services\MyHttpService_" + port))
            {
                if (key != null)
                {
                    key.SetValue("Port", port);
                }
            }
        }

        CloseServiceHandle(service);
        CloseServiceHandle(scm);
    }

    public static void UninstallService(int port)
    {
        string portSuffix = "_" + port;
        string serviceNameToDelete = null;

        // 使用 WMI 枚举所有服务
        ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Service");
        foreach (ManagementObject service1 in searcher.Get())
        {
            string serviceName = service1["Name"]?.ToString();
            if (serviceName != null && serviceName.EndsWith(portSuffix))
            {
                serviceNameToDelete = serviceName;
                break;
            }
        }

        if (serviceNameToDelete == null)
        {
            Console.WriteLine($"未找到以端口号 {port} 结尾的服务");
            return;
        }

        IntPtr scm = OpenSCManager(null, null, 0x0001); // SC_MANAGER_CONNECT
        if (scm == IntPtr.Zero)
        {
            Console.WriteLine("无法打开服务控制管理器");
            return;
        }

        IntPtr service = OpenService(scm, serviceNameToDelete, 0x0020 | 0x00010000 | 0x0004); // SERVICE_QUERY_STATUS | DELETE | SERVICE_STOP
        if (service == IntPtr.Zero)
        {
            Console.WriteLine($"无法打开服务: {serviceNameToDelete}");
        }
        else
        {
            // 检查服务状态
            SERVICE_STATUS status = new SERVICE_STATUS();
            if (QueryServiceStatus(service, ref status))
            {
                if (status.dwCurrentState != 0x00000001) // SERVICE_STOPPED
                {
                    // 停止服务
                    Console.WriteLine($"正在停止服务: {serviceNameToDelete}");
                    ControlService(service, 0x00000001, ref status); // SERVICE_CONTROL_STOP

                    // 等待服务停止
                    while (status.dwCurrentState != 0x00000001) // SERVICE_STOPPED
                    {
                        Console.WriteLine($"等待服务停止: {serviceNameToDelete} 当前状态: {status.dwCurrentState}");
                        Thread.Sleep(1000); // 等待一秒
                        QueryServiceStatus(service, ref status);
                    }
                    Console.WriteLine($"服务 {serviceNameToDelete} 已停止");
                }
            }

            // 删除服务
            if (DeleteService(service))
            {
                Console.WriteLine($"服务 {serviceNameToDelete} 卸载成功");
            }
            else
            {
                Console.WriteLine($"服务 {serviceNameToDelete} 卸载失败");
            }
        }

        CloseServiceHandle(service);
        CloseServiceHandle(scm);
    }

    // P/Invoke declarations
    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, uint dwDesiredAccess);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern IntPtr CreateService(
        IntPtr hSCManager,
        string lpServiceName,
        string lpDisplayName,
        uint dwDesiredAccess,
        uint dwServiceType,
        uint dwStartType,
        uint dwErrorControl,
        string lpBinaryPathName,
        string lpLoadOrderGroup,
        IntPtr lpdwTagId,
        string lpDependencies,
        string lpServiceStartName,
        string lpPassword);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool DeleteService(IntPtr hService);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool CloseServiceHandle(IntPtr hSCObject);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool QueryServiceStatus(IntPtr hService, ref SERVICE_STATUS lpServiceStatus);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool ControlService(IntPtr hService, uint dwControl, ref SERVICE_STATUS lpServiceStatus);

    [StructLayout(LayoutKind.Sequential)]
    private struct SERVICE_STATUS
    {
        public uint dwServiceType;
        public uint dwCurrentState;
        public uint dwControlsAccepted;
        public uint dwWin32ExitCode;
        public uint dwServiceSpecificExitCode;
        public uint dwCheckPoint;
        public uint dwWaitHint;
    }
}
